/*
 * Copyright (C) 2010 Graham Allan
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

package edu.strath.cis.grallan.findbugs.adaptiveranking.gui;

import java.awt.Component;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

import edu.strath.cis.grallan.findbugs.adaptiveranking.AbstractAdaptiveRanker;
import edu.strath.cis.grallan.findbugs.adaptiveranking.AdaptiveRankingMode;
import edu.strath.cis.grallan.findbugs.adaptiveranking.SwingRankingMode;
import edu.strath.cis.grallan.findbugs.adaptiveranking.arm.ARMRank;
import edu.strath.cis.grallan.findbugs.adaptiveranking.arm.ARMRanker;
import edu.strath.cis.grallan.findbugs.adaptiveranking.gui.sort.ARMRankSortable;
import edu.strath.cis.grallan.findbugs.adaptiveranking.gui.sort.LearningValueSortable;
import edu.strath.cis.grallan.findbugs.adaptiveranking.lr.LearningRank;
import edu.strath.cis.grallan.findbugs.adaptiveranking.lr.LearningValueRanker;
import edu.strath.cis.grallan.findbugs.adaptiveranking.population.PopulationExtractor;
import edu.umd.cs.findbugs.gui2.ApplicationDisplayIssueDecider;
import edu.umd.cs.findbugs.gui2.BugDesignationListener.BugDesignationSubject;
import edu.umd.cs.findbugs.gui2.BugLeafNode;
import edu.umd.cs.findbugs.gui2.BugSelectionListener;
import edu.umd.cs.findbugs.gui2.BugSet;
import edu.umd.cs.findbugs.gui2.BugSetFactory;
import edu.umd.cs.findbugs.gui2.BugTreeModel;
import edu.umd.cs.findbugs.gui2.BugTreePopupProvider;
import edu.umd.cs.findbugs.gui2.DisplayIssueDecider;
import edu.umd.cs.findbugs.gui2.IApplicationState;
import edu.umd.cs.findbugs.gui2.IViewController;
import edu.umd.cs.findbugs.gui2.MainFrame;
import edu.umd.cs.findbugs.gui2.sort.SorterTableColumnModel;

/**
 * @author Graham Allan (grallan@cis.strath.ac.uk)
 */
public class AdaptiveRankingPanelProvider {

	private final Executor rankingExecutor;
	private BugSetFactory bugSetFactory;
	private IApplicationState applicationState;
	private BugDesignationSubject bugDesignationSubject;
	private BugTreePopupProvider popupProvider;
	private MainFrame mainFrame;
	private BugSelectionListener bugSelectionListener;
	private IViewController viewController;
	private PopulationExtractor extractorPrototype;
	private RankingViewController rankingViewController;
	private ApplicationDisplayIssueDecider applicationDisplayIssueDecider;

	public AdaptiveRankingPanelProvider() {
		rankingExecutor = Executors.newFixedThreadPool(2);
	}

	public AdaptiveRankingPanel makeAdaptiveRankingPanel(IApplicationState applicationState,
			BugDesignationSubject bugDesignationSubject, BugTreePopupProvider popupProvider, MainFrame mainFrame,
			BugSelectionListener bugSelectionListener, IViewController viewController) {

		this.bugDesignationSubject = bugDesignationSubject;
		this.applicationState = applicationState;
		this.popupProvider = popupProvider;
		this.mainFrame = mainFrame;
		this.bugSelectionListener = bugSelectionListener;
		this.viewController = viewController;

		this.extractorPrototype = PopulationExtractor.instanceFor(applicationState.bugCollection());
		this.rankingViewController = new RankingViewController(viewController);

		DisplayIssueDecider displayAllButDead = DisplayIssueDecider.DISPLAY_ALL_BUT_DEAD;
		this.applicationDisplayIssueDecider = new ApplicationDisplayIssueDecider(applicationState)
				.chainDecider(displayAllButDead);
		this.bugSetFactory = new BugSetFactory(applicationDisplayIssueDecider);

		List<SwingRankingMode> modes = new ArrayList<SwingRankingMode>();
		modes.add(makeLearningModePanel());
		modes.add(makeARMRankMode());

		AdaptiveRankingPanel adaptiveRankingPanel = new AdaptiveRankingPanel(modes);
		rankingViewController.setAdaptiveRankingPanel(adaptiveRankingPanel);

		return adaptiveRankingPanel;
	}

	private AbstractSwingRankingMode<ARMRank> makeARMRankMode() {

		ARMRanker armRanker = new ARMRanker(applicationState, extractorPrototype);
		bugDesignationSubject.addBugDesignationListener(armRanker);
		applicationState.addProjectChangeListener(armRanker);

		RankedBugTree armRankTree = new RankedBugTree(applicationState, popupProvider, armRanker);
		armRankTree.addBugSelectionListener(bugSelectionListener);
		ARMRankSortable armRankSortable = new ARMRankSortable("ARM-RANK", armRanker);
		SorterTableColumnModel armRankSorter = new SorterTableColumnModel(Arrays.asList(armRankSortable));
		BugTreeModel armRankModel = new BugTreeModel(armRankTree, armRankSorter, new BugSet(
				new ArrayList<BugLeafNode>(), mainFrame), applicationState.uiFactory().filterActivity());
		armRankTree.setModel(armRankModel);

		AbstractSwingRankingMode<ARMRank> armRankMode = new ARMRankMode(armRanker, armRankTree, rankingViewController,
				rankingExecutor, bugSetFactory, applicationDisplayIssueDecider);
		armRankModel.setTreeHolder(armRankMode);
		armRanker.addRankProgressCallback(new RankingModeProgressMonitor(mainFrame, viewController, armRankMode,
				"Calculating rank of each bug alert."));

		return armRankMode;
	}

	private AbstractSwingRankingMode<LearningRank> makeLearningModePanel() {

		AbstractAdaptiveRanker<LearningRank> learningValueRanker = new LearningValueRanker(applicationState,
				extractorPrototype);
		bugDesignationSubject.addBugDesignationListener(learningValueRanker);
		applicationState.addProjectChangeListener(learningValueRanker);

		RankedBugTree learningTree = new RankedBugTree(applicationState, popupProvider, learningValueRanker);
		learningTree.addBugSelectionListener(bugSelectionListener);
		LearningValueSortable sortable = new LearningValueSortable("Learning Value", learningValueRanker);
		SorterTableColumnModel learningSorter = new SorterTableColumnModel(Arrays.asList(sortable));
		BugTreeModel learningModel = new BugTreeModel(learningTree, learningSorter, new BugSet(
				new ArrayList<BugLeafNode>(), applicationDisplayIssueDecider), applicationState.uiFactory()
				.filterActivity());
		learningTree.setModel(learningModel);

		AbstractSwingRankingMode<LearningRank> learningMode = new LearningMode(learningValueRanker, learningTree,
				rankingViewController, rankingExecutor, bugSetFactory, applicationDisplayIssueDecider);
		learningModel.setTreeHolder(learningMode);

		Component parent = applicationState.uiFactory().dialogParent();
		learningValueRanker.addRankProgressCallback(new RankingModeProgressMonitor(parent, viewController,
				learningMode, "Calculating learning value of each bug alert."));

		return learningMode;
	}

	private static class RankingViewController implements IRankingViewController {

		private final IViewController showHideDelegate;
		private AdaptiveRankingPanel adaptiveRankingPanel;

		public RankingViewController(IViewController showHideDelegate) {
			this.showHideDelegate = showHideDelegate;

		}

		void setAdaptiveRankingPanel(AdaptiveRankingPanel adaptiveRankingPanel) {
			this.adaptiveRankingPanel = adaptiveRankingPanel;
		}

		public DisplayState isDisplayedMode(AdaptiveRankingMode mode) {
			if (adaptiveRankingPanel == null)
				return DisplayState.NON_EXISTENT;

			return adaptiveRankingPanel.isDisplayedMode(mode);
		}

		public void hideView() {
			showHideDelegate.hideView();
		}

		public void showView() {
			showHideDelegate.showView();

		}

	}
}
